package edu.neu.cs6515.test.runner;

import java.util.List;

import javax.xml.bind.JAXBException;

import edu.neu.cs6515.board.HexagonBoard;
import edu.neu.cs6515.xml.Bad;
import edu.neu.cs6515.xml.Board;
import edu.neu.cs6515.xml.Placement;
import edu.neu.cs6515.xml.Results;
import edu.neu.cs6515.xml.XMLResultMarshaller;

/**
 * Parent class for all TestRunners, provides basic initalization of tests
 */
public abstract class AbstractTestRunner {

    protected static final int MAX_PLAYERS = 6;
    protected static final int MIN_PLAYERS = 2;
    protected static final String XML_INVALID = "INVALID-XML";
    protected static final String INVALID_NUMBER_OF_PLAYERS = "INVALID-NUMBER-OF-PLAYERS";

    protected final Board boardFromXML;
    protected final HexagonBoard board;
    protected final Results gameResults = new Results();

    /**
     * C'tor, initializes a hexagon board and places the initial tiles
     * 
     * @param boardFromXML
     *            board containing the info to prepare the board
     */
    public AbstractTestRunner(final Board boardFromXML) {
        this.boardFromXML = boardFromXML;
        board = new HexagonBoard(boardFromXML.getPlayers());
        initializePlacements(boardFromXML.getPlacement());
    }

    /**
     * Applies list of initial placements to board
     * 
     * @param placements
     *            Placements to init board
     */
    protected abstract void initializePlacements(
            final List<Placement> placements);

    /**
     * Initializes the game, runs it and returns the xml result string
     * 
     * @return xml string, reporting about the outcome of the moves
     */
    public String runGameAndGetResults() {
        final int players = boardFromXML.getPlayers();
        if (players < MIN_PLAYERS || players > MAX_PLAYERS) {
            throw new IllegalArgumentException("Number of Players: " + players);
        }
        try {
            return runGameFromCorrectXML();
        } catch (final JAXBException e) {
            return gameInitFailed(XML_INVALID);
        } catch (final IllegalArgumentException e) {
            return gameInitFailed(INVALID_NUMBER_OF_PLAYERS);
        }
    }

    /**
     * Initializes the game, runs it and returns the xml result string
     * 
     * @return xml string, reporting about the outcome of the moves
     */
    protected String runGameFromCorrectXML() throws JAXBException {
        return new XMLResultMarshaller().marshall(gameResults);
    }

    /**
     * Returns an XML result containing a "bad" element
     * 
     * @param reason
     *            to be stated in the bad element
     * @return XML result containing one "bad" element
     */
    protected String gameInitFailed(final String reason) {
        final Results results = new Results();
        results.getBad().add(new Bad(reason));
        try {
            return new XMLResultMarshaller().marshall(results);
        } catch (final JAXBException e1) {
            System.out.println("Unable to generate result xml");
            return "";
        }
    }
}
